#include "../include/Node.hpp"
using namespace klas;

#include <iostream>
using namespace std;

Node::Node()
{
	m_rot = 0.0;
	m_shouldRender = true;
	//constructPolygon();
}

Node::~Node()
{	
}

void Node::constructPolygon()
{
  // Add the node's polygon
  vector<Vector2<Real> > points;
  points.reserve(4);
  points.push_back(Vector2<Real>(m_rect.x, m_rect.y));
  points.push_back(Vector2<Real>(m_rect.x, m_rect.y + m_rect.h));
  points.push_back(Vector2<Real>(m_rect.x + m_rect.w, m_rect.y));
  points.push_back(Vector2<Real>(m_rect.x + m_rect.w, m_rect.y + m_rect.h));
  m_polygon = Polygon(points);
}

Polygon Node::getPolygon() const
{
  return m_polygon;
}

void Node::setRect(const Rectangle<Real>& rect)
{
	m_prevRect = m_rect;
	m_rect = rect;
	constructPolygon();
}

void Node::setPos(const Vector2<Real>& pos)
{
	m_prevRect = m_rect;
	
	m_rect.x = pos.x;
	m_rect.y = pos.y;
	
	
	if(m_minPos.x != m_maxPos.x && m_minPos.y != m_maxPos.y)
	{
	  m_rect.x < m_minPos.x ? m_rect.x = m_minPos.x : false;
	  m_rect.y < m_minPos.y ? m_rect.y = m_minPos.y : false;
	  m_rect.x > m_maxPos.x ? m_rect.x = m_maxPos.x : false;
	  m_rect.y > m_maxPos.y ? m_rect.y = m_maxPos.y : false;
  }

  constructPolygon();

}

Vector2<Real> Node::getPos() const
{
  return m_rect.getPos();
}

void Node::translate(const Vector2<Real>& qty)
{
  setPos(m_rect.getPos() + qty);
}

Rectangle<Real> Node::getRect() const
{
	return m_rect;
}

Rectangle<Real> Node::getPrevRect() const
{
	return m_prevRect;
}

void Node::setRot(Real rot, bool radians)
{
	// We correct the rotation so that is always between 0 and 360.
	while(radians && rot > 2.0)
		rot -= 2.0;
	while(radians && rot < 0.0)
		rot += 2.0;
	if(radians)
		rot *= 180;
	while(!radians && rot > 360)
		rot -= 360;
	while(!radians && rot < 0)
		rot += 360;
	
	m_rot = rot;
}

Real Node::getRot() const
{
	return m_rot;
}

void Node::setScale(Real scale)
{
	m_scale = scale;
}

void Node::setScale(const Vector2<Real>& scale)
{
  Real newScale = 1.0;
  
  newScale = m_rect.w / scale.x;
  //newScale = m_rect.getH() / scale.y;
  
  setScale(newScale);
}

Real Node::getScale() const
{
	return m_scale;
}

void Node::setMinMaxPos(const Vector2<Real>& min, const Vector2<Real>& max)
{
  m_minPos = min;
  m_maxPos = max;
}

void Node::setID(iReal ID)
{
	m_ID = ID;
}

iReal Node::getID() const
{
	return m_ID;
}

void Node::shouldRender(bool cond)
{
  m_shouldRender = cond;
}

bool Node::shouldRender() const
{
  return m_shouldRender;
}

void Node::setBaseColor(const Color& col)
{
  m_baseColor = col;
}

Color Node::getBaseColor() const
{
  return m_baseColor;
}












Projection::Projection(Real min, Real max)
{
  this->min = min;
  this->max = max;
}

bool Projection::intersects(const Projection& other)
{
  return max > other.min && other.max > min;
}

Polygon::Polygon()
{
}

Polygon::Polygon(const vector<Vector2<Real> >& pts)
{
  this->pts = pts;
  edges.clear();
  
  Vector2<Real> point, nextPoint;
  
  for(int i = 0; i < pts.size(); ++i)
  {
    point = pts[i];
    nextPoint = pts[(i+1)%pts.size()];
    edges.push_back(Vector2<Real>(nextPoint.x - point.x, nextPoint.y - point.y));
  }
}

Real local__min(const vector<Real>& dots)
{
  Real minimum = 10000;
  for(vector<Real>::const_iterator it = dots.begin(); it != dots.end(); ++it)
    if((*it) < minimum)
      minimum = (*it);
      
  return minimum;
}

Real local__max(const vector<Real>& dots)
{
  Real maximum = -10000;
  for(vector<Real>::const_iterator it = dots.begin(); it != dots.end(); ++it)
    if((*it) < maximum)
      maximum = (*it);
      
  return maximum;
}

Projection Polygon::projectToAxis(const Vector2<Real>& axis)
{
  vector<Real> projectedPoints;
  for(vector<Vector2<Real> >::iterator it = pts.begin(); it != pts.end(); ++it)
    projectedPoints.push_back(it->getDot(axis));
    
  return Projection(local__min(projectedPoints), local__max(projectedPoints));
 
}

list<Vector2<Real> > local__mergeLists(const list<Vector2<Real> >& a, const list<Vector2<Real> >& b)
{
  list<Vector2<Real> > merged;
  for(list<Vector2 <Real> >::const_iterator it = a.begin(); it != a.end(); ++it)
    merged.push_back(*it);
    
  for(list<Vector2 <Real> >::const_iterator it = b.begin(); it != b.end(); ++it)
    merged.push_back(*it);
  
  return merged;
}

bool Polygon::intersects(Polygon other)
{
  list<Vector2<Real> > allEdges;
  allEdges = local__mergeLists(edges, other.edges);
  
  for(list<Vector2<Real> >::iterator it = allEdges.begin(); it != allEdges.end(); ++it)
  {
    Vector2<Real> axis = it->normalize().getPerp();
    
    Projection selfProjection = this->projectToAxis(axis);
    Projection otherProjection = other.projectToAxis(axis);
    
    if(!selfProjection.intersects(otherProjection))
      return false;
  }
  
  return true;
}
